﻿using Common;
using Linguist.Acoustic;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Linguist.LexTree
{
    /// <summary>
    ///  A node that represents an HMM in the hmm tree
    /// </summary>
    public class HMMNode: UnitNode
    {
        private IHMM hmm;

        // There can potentially be a large number of nodes (millions),
        // therefore it is important to conserve space as much as
        // possible.  While building the HMMNodes, we keep right contexts
        // in a set to allow easy pruning of duplicates.  Once the tree is
        // entirely built, we no longer need to manage the right contexts
        // as a set, a simple array will do. The freeze method converts
        // the set to the array of units.  This rcSet object holds the set
        // during construction and the array after the freeze.

        private Object rcSet;


        /**
        /// Creates the node, wrapping the given hmm
         *
        /// @param hmm the hmm to hold
         */
        public HMMNode(IHMM hmm, float probablilty) 
            :base(probablilty)
        {
            
            this.hmm = hmm;

            IUnit _base = getBaseUnit();

            Type = SIMPLE_UNIT;
            if (_base.isSilence()) 
            {
                Type = SILENCE_UNIT;
            } 
            else if (_base.isFiller()) 
            {
                Type = FILLER_UNIT;
            } 
            else if (hmm.getPosition() == HMMPosition.BEGIN) 
            {
                Type = WORD_BEGINNING_UNIT;
            }

        }


        /**
        /// Returns the base unit for this hmm node
         *
        /// @return the base unit
         */
        override
        public IUnit getBaseUnit() 
        {
            // return hmm.getUnit().getBaseUnit();
            return hmm.getBaseUnit();
        }


        /**
        /// Returns the hmm for this node
         *
        /// @return the hmm
         */
        public IHMM getHMM() 
        {
            return hmm;
        }


        override
        public HMMPosition getPosition() 
        {
            return hmm.getPosition();
        }


        override
        public Object getKey() 
        {
            return getHMM();
        }


        /**
        /// Returns a string representation for this object
         *
        /// @return a string representation
         */
        override
        public String ToString() 
        {
            return "HMMNode " + hmm + " p " +  LogUnigramProbability.ToString();
        }


        /**
        /// Adds a right context to the set of possible right contexts for this node. This is typically only needed for hmms
        /// at the ends of words.
         *
        /// @param rc the right context.
         */
        public void addRC(IUnit rc) 
        {
            getRCSet().Add(rc);
        }


        /** Freeze this node. Convert the set into an array to reduce memory overhead */
        public void freeze() 
        {
            base.freeze();
            if (rcSet is List<IUnit>) 
            {
                List<IUnit> set = (List<IUnit>) rcSet;
                rcSet = set.ToArray();
            }
        }


        /**
        /// Gets the rc as a set. If we've already been frozen it is an error
         *
        /// @return the set of right contexts
         */
        private List<IUnit> getRCSet() 
        {
            if (rcSet == null) {
                rcSet = new List<Unit>();
            }

            Trace.Assert(rcSet is List<IUnit>);
            return (List<IUnit>) rcSet;
        }


        /**
        /// returns the set of right contexts for this node
         *
        /// @return the set of right contexts
         */
        public IUnit[] getRC() 
        {
            if (rcSet is List<IUnit>) 
            {
                freeze();
            }
            return (Unit[]) rcSet;
        }

    }
}
